package com.zhike.mobileimsdk.server;

import java.io.IOException;

import com.zhike.mobileimsdk.server.event.MessageQoSEventListenerS2C;
import com.zhike.mobileimsdk.server.event.ServerEventListener;
import com.zhike.mobileimsdk.server.network.Gateway;
import com.zhike.mobileimsdk.server.network.GatewayTCP;
import com.zhike.mobileimsdk.server.network.GatewayUDP;
import com.zhike.mobileimsdk.server.network.GatewayWebsocket;
import com.zhike.mobileimsdk.server.processor.OnlineUserManager;
import com.zhike.mobileimsdk.server.qos.QoS4ReciveDaemonC2S;
import com.zhike.mobileimsdk.server.qos.QoS4SendDaemonS2C;
import com.zhike.mobileimsdk.server.utils.ZkUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class ServerLauncher {
	private static Logger logger = LoggerFactory.getLogger(ServerLauncher.class);

	public static boolean serverTimestamp = false;
	public static boolean bridgeEnabled = false;
	public static int supportedGateways = 0;

	protected ServerCoreHandler serverCoreHandler = null;
	private boolean running = false;

	public static String nodeName;
	private Gateway udp = null;
	private Gateway tcp = null;
	private Gateway ws = null;

	private ZkUtil zkUtil = null;

	public ServerLauncher() throws IOException {
		// default do nothing
	}

	protected ServerCoreHandler initServerCoreHandler() {
		return new ServerCoreHandler();
	}

	protected abstract void initListeners();

	protected void initGateways() throws Exception {
		if (Gateway.isSupportUDP(supportedGateways)) {
			udp = createGatewayUDP();
			udp.init(this.serverCoreHandler);
		}

		if (Gateway.isSupportTCP(supportedGateways)) {
			tcp = createGatewayTCP();
			tcp.init(this.serverCoreHandler);
		}

		if (Gateway.isSupportWebSocket(supportedGateways)) {
			ws = createGatewayWebsocket();
			ws.init(this.serverCoreHandler);
		}

	}

	protected GatewayUDP createGatewayUDP() {
		return new GatewayUDP(zkUtil);
	}

	protected GatewayTCP createGatewayTCP() {
		return new GatewayTCP(zkUtil);
	}

	protected GatewayWebsocket createGatewayWebsocket() {
		return new GatewayWebsocket(zkUtil);
	}

	public void startup() throws Exception {
		shutdownHook();
		if (!this.running) {
			serverCoreHandler = initServerCoreHandler();
			initListeners();
			if (ZkUtil.ZK_ENABLE) {
				zkUtil = new ZkUtil();
				zkUtil.connection();
			}
			initGateways();
			QoS4ReciveDaemonC2S.getInstance().startup();
			QoS4SendDaemonS2C.getInstance().startup(true).setServerLauncher(this);

			if (ServerLauncher.bridgeEnabled) {
				serverCoreHandler.lazyStartupBridgeProcessor();
				logger.info("[IMCORE] 配置项：已开启与MobileIMSDK Web的互通.");
			} else {
				logger.info("[IMCORE] 配置项：未开启与MobileIMSDK Web的互通.");
			}

			bind();
			this.running = true;
		} else {
			logger.warn("[IMCORE] 基于MobileIMSDK的通信服务正在运行中，本次startup()失败，请先调用shutdown()后再试！");
		}
	}

	protected void bind() throws Exception {
		if (udp != null)
			udp.bind();
		if (tcp != null)
			tcp.bind();
		if (ws != null)
			ws.bind();
	}

	public void shutdown() {
		if (udp != null)
			udp.shutdown();
		if (tcp != null)
			tcp.shutdown();
		if (ws != null)
			ws.shutdown();

		QoS4ReciveDaemonC2S.getInstance().stop();
		QoS4SendDaemonS2C.getInstance().stop();
		zkUtil.delRegistryInfo();
		OnlineUserManager.getInstance().userOfflineFromServer(nodeName);
		this.running = false;
	}

	private void shutdownHook() {
		Runtime.getRuntime().addShutdownHook(new Thread(() -> {
			logger.debug("优雅停机start");
			shutdown();
			logger.debug("优雅停机end");
		}));
	}

	public ServerEventListener getServerEventListener() {
		return serverCoreHandler.getServerEventListener();
	}

	public void setServerEventListener(ServerEventListener serverEventListener) {
		this.serverCoreHandler.setServerEventListener(serverEventListener);
	}

	public MessageQoSEventListenerS2C getServerMessageQoSEventListener() {
		return serverCoreHandler.getServerMessageQoSEventListener();
	}

	public void setServerMessageQoSEventListener(MessageQoSEventListenerS2C serverMessageQoSEventListener) {
		this.serverCoreHandler.setServerMessageQoSEventListener(serverMessageQoSEventListener);
	}

	public ServerCoreHandler getServerCoreHandler() {
		return serverCoreHandler;
	}

	public boolean isRunning() {
		return running;
	}
}
